package com.iris.live.services.services.impl;

import com.google.common.collect.Lists;
import com.google.gson.JsonObject;
import com.iris.live.services.common.ApprovalUtils;
import com.iris.live.services.common.JPush;
import com.iris.live.services.common.JsonObjectUtils;
import com.iris.live.services.common.LshMsgUtils;
import com.iris.live.services.common.reconsitution.DefaultValueConstant;
import com.iris.live.services.common.reconsitution.MessageContext;
import com.iris.live.services.common.reconsitution.MessageType;
import com.iris.live.services.data.models.*;
import com.iris.live.services.data.repositories.*;
import com.iris.live.services.models.PageData;
import com.iris.live.services.models.ResultData;
import com.iris.live.services.services.ApprovalService;
import com.iris.live.services.services.CarTransferService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static com.iris.live.services.common.reconsitution.MessageType.MSG_TYPE_SHUNTING_IN;

/**
 * Created by DF on 3/14/2017
 */
@Service
@Transactional
class CarTransferServiceImpl implements CarTransferService {
    private static Logger logger = LoggerFactory.getLogger(CarTransferServiceImpl.class);
    @Autowired
    private Lsh库存表Repository stockRep;
    @Resource(name = "carRepository")
    private Lsh车型Repository carRep;
    @Autowired
    private Lsh库存内部可见Repository stockVisibleRep;
    @Autowired
    private CarTransferLogRepository carTransLogRep;
    @Autowired
    private CarTransferRepository carTransRep;
    @Autowired
    private PushApprovalItemSettingRepository workFlowSetRep;
    @Autowired
    private PushApprovalWorkFlowRepository2 workFlowFrameRep;
    @Autowired
    private Lsh经销商表Repository dealerRep;
    @Resource(name = "userRepository")
    private 用户Repository userRep;
    @Resource(name = "approvalService")
    private ApprovalService approvalService;
    @Resource(name = "messageSettingRepository")
    private MessageSettingRepository msgSetRep;

    @Override
    public ResultData startCarTransfer(CarTransferLogModel model, String dealer, String username) {
        logger.info("startCarTransfer, params json = " + JsonObjectUtils.writeAsJson(model));
        // 参数校验
        Lsh库存表Model stockModel = stockRep.findOne(model.getStockCode());
        if (stockModel == null) return new ResultData("false", "找不到对应的库存", null);

        String errMsg = "开始调车流程异常";
        try {
            // 检查该车是否可调
            ResultData resultData = isTransferable(dealer, stockModel);
            if ("false".equals(resultData.getResult())) {
                errMsg = resultData.getMessage();
                throw new Exception();
            }
            // 初始化库存表，前端不好处理调出经销商，由后台处理
            Integer updatedCount = stockRep.initStockInTransfer(model.getStockCode(), model.getSc(), model.getReason(), model.getArrangedMoney(),
                    model.getInDealer(), stockModel.get所属经销商(), model.getLogisticsStatus(), Date.valueOf(LocalDate.now()));
            // 如果更新了0条记录，表示请求并发时，该记录已经被其他请求修改了
            if (updatedCount == 0) {
                errMsg = "该车已经被其他人调走，请刷新页面";
                throw new Exception();
            }
            // 前端不好处理调出经销商，由后台处理
            model.setOutDealer(stockModel.get所属经销商());
            // 初始化car_transfer_log
            carTransLogRep.save(model);
            // 初始化库存内部可见表
            Lsh库存表Model store = stockRep.findOne(model.getStockCode());
            // 更改车辆的内部可见为不可见
            Lsh库存内部可见Model model内部 = stockVisibleRep.findBystocknumber(store.get库存编号());
            if (model内部 == null) { // 不存在可见记录，新增
                Lsh库存内部可见Model visibleModel = new Lsh库存内部可见Model();
                visibleModel.set内部可见角色("SC/CDO不可见");
                visibleModel.set库存编号(store.get库存编号());
                visibleModel.set更新时间(Timestamp.valueOf(LocalDateTime.now()));
                visibleModel.set更新账号("Admin");
                stockVisibleRep.save(visibleModel);
            } else { // 存在可见记录，修改
                stockVisibleRep.updateStatusById("SC/CDO不可见", model内部.get库存内部可见编号());
            }
            // 审批流程初始化
            PushApprovalWorkFlowModel pModel = new PushApprovalWorkFlowModel();
            pModel.setPermit(model.getInDealer());
            pModel.setType(ApprovalUtils.TRANSFER_IN);
            pModel.setQuotedPriceCodeOrVin(model.getId() + "");
            ResultData rd = approvalService.addApprovalWorkFlow(pModel, username);
            if ("false".equals(rd.getResult())) {
                errMsg = rd.getMessage();
                throw new Exception();
            } else {
                errMsg = model.getId() + "";
            }
            return new ResultData("true", errMsg, null);
        } catch (Exception e) {
            logger.error(errMsg, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new ResultData("false", errMsg, null);
        }
    }

    @Override
    public ResultData getTransferApprovalPagedList(getTransferApprovalPagedList request) {
        logger.info("getTransferApprovalPagedList, params json = " + JsonObjectUtils.writeAsJson(request));
        PageData pageData = this.carTransRep.getTransferApprovalPagedList(request);
        if (0 == pageData.getTotal()) {
            return new ResultData("true", "暂无记录", null);
        } else {
            return new ResultData("true", null, pageData);
        }
    }

    @Override
    public ResultData getTransferInDetail(Integer transferId) {
        logger.info("getTransferDetailInfo, params json = " + JsonObjectUtils.writeAsJson(transferId));
        List reList = this.carTransRep.getTransferInDetail(transferId);
        return new ResultData("true", null, new PageData(reList, reList.size()));
    }

    @Override
    public ResultData getTransferOutDetail(Integer transferId) {
        logger.info("getTransferOutDetail, params json = " + JsonObjectUtils.writeAsJson(transferId));
        List reList = this.carTransRep.getTransferOutDetail(transferId);
        return new ResultData("true", null, new PageData(reList, reList.size()));
    }

    @Override
    public ResultData getTransferApprovalHistory(String transactionCode, String username) {
        logger.info("getTransferApprovalHistory, params json = " + JsonObjectUtils.writeAsJson(transactionCode));
        List reList = this.carTransRep.getTransferApprovalHistory(transactionCode);
        return new ResultData("true", null, new PageData(reList, reList.size()));
    }

    @Override
    public ResultData agreeTransferInApproval(CarTransferService.AgreeTransferInApproval request) {
        logger.info("agreeTransferInApproval，params json = " + JsonObjectUtils.writeAsJson(request));
        String errMsg = "调车调入审批通过异常";
        try {
            // 根据id获取待修改的审批记录
            PushApprovalWorkFlowModel currMo = workFlowFrameRep.findOne(request.transactionId);
            if (currMo == null) {
                errMsg = "找不到对应的审批记录";
                throw new Exception();
            }
            // 修改审批记录并保存
            if ("0".equals(currMo.getApprovalStatus())) {
                currMo.setApprovalStatus(ApprovalUtils.AGREE);
                currMo.setRemark(request.remark);
                currMo.setProcessTime(Timestamp.valueOf(LocalDateTime.now()));
                workFlowFrameRep.save(currMo);
            } else {
                errMsg = "该审批流水ID已经处理过";
                throw new Exception();
            }
            // 获取记录对应的审批step
            String currentStep = currMo.getStep();
            // 获取全部调入审批流水
            List<PushApprovalWorkFlowModel> transInWorkFlow = workFlowFrameRep.getModelByTransactionCode(currMo.getTranscationCode());
            // 排序
            transInWorkFlow.sort((PushApprovalWorkFlowModel m1, PushApprovalWorkFlowModel m2) -> m1.getStep().compareTo(m2.getStep()));
            // 获取当前审批人在流水中的索引
            Integer currIndex = getIndex(transInWorkFlow, currentStep);
            if (currIndex == -1) {
                errMsg = "在流水中找不到对应的审批step";
                throw new Exception();
            }
            // 修改调车表记录
            Integer transferId = Integer.parseInt(currMo.getQuotedPriceCodeOrVin());
            CarTransferLogModel transLogMo = carTransLogRep.findOne(transferId);
            transLogMo.setInternalApprovalDate(Date.valueOf(LocalDate.now()));
            transLogMo.setInternalApprovalUser(currMo.getUserName());
            carTransLogRep.save(transLogMo);
            // 消息数据准备
            Lsh库存表Model stockMo = stockRep.findOne(transLogMo.getStockCode());
            Lsh车型Model carMo = carRep.findOne(stockMo.get车型编号());
            String stepNum = currentStep.substring(4);
            if (!currIndex.equals(transInWorkFlow.size() - 1)) { // 如果审批没到最后一级
                String msgContent;
                if ("".equals(transLogMo.getCustomName())) { // 无客户调车
                    String[] noCusMsgPar = {stockMo.get生产号(), carMo.get车型详细(), stepNum};
                    msgContent = MessageFormat.format("生产号为{0},车款为{1}的调车调入{2}级审批已通过,非客户调车", (Object[]) noCusMsgPar);
                } else { // 有客户调车
                    String[] cusMsgPar = {stockMo.get生产号(), carMo.get车型详细(), stepNum, transLogMo.getCustomName(), transLogMo.getCustomTel()};
                    msgContent = MessageFormat.format("生产号为{0},车款为{1}的调车调入{2}级审批已通过,客户姓名：{3},顾客电话：{4}", (Object[]) cusMsgPar);
                }
                // 保存给销售行政的消息
                LshMsgUtils.getLshMsg(transLogMo.getInDealer(), currMo.getUserName(),
                        transLogMo.getInDealer(), transLogMo.getInternalApplyUser(),
                        MessageType.Type.getName(MSG_TYPE_SHUNTING_IN),
                        msgContent, currMo.getUserName(), transLogMo.getCustomTel());
                // 保存给下级审批人的消息
                LshMsgUtils.getLshMsg(currMo.getPermit(), currMo.getUserName(),
                        transInWorkFlow.get(currIndex + 1).getPermit(), transInWorkFlow.get(currIndex + 1).getUserName(),
                        MessageType.Type.getName(MSG_TYPE_SHUNTING_IN),
                        msgContent, currMo.getUserName(), transLogMo.getCustomTel());
                // 极光推送给下级审批人
                JsonObject json = JsonObjectUtils.getJsonObject(currMo.getType() + "", ApprovalUtils.AGREE, stockMo.get车架号(), null, null, null);
                List<String> recList = Lists.newArrayList();
                recList.add(transInWorkFlow.get(currIndex + 1).getUserName());
                JPush.sendMsgToMgtAi(msgContent, msgContent, json, recList);
                return new ResultData("true", null, null);
            } else { // 如果到达最后一级审批
                // 调入审批通过后处理方法
                errMsg = postCarTransferInAgreedProcess(transInWorkFlow, currMo);
                if ("00".equals(errMsg)) { // 正常返回
                    return new ResultData("true", null, null);
                } else { // 异常返回
                    throw new Exception();
                }
            }
        } catch (Exception e) {
            logger.error(errMsg, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new ResultData("false", errMsg, null);
        }
    }

    @Override
    public ResultData disagreeTransferInApproval(CarTransferService.AgreeTransferInApproval request) {
        logger.info("disagreeTransferInApproval，params json = " + JsonObjectUtils.writeAsJson(request));
        String errMsg = "调入审批驳回后处理异常";
        try {
            // 根据id获取待修改的审批记录
            PushApprovalWorkFlowModel currMo = workFlowFrameRep.findOne(request.transactionId);
            if (currMo == null) {
                errMsg = "找不到对应的审批记录";
                throw new Exception();
            }
            // 修改审批记录并保存
            currMo.setApprovalStatus(ApprovalUtils.DISAGREE);
            currMo.setRemark(request.remark);
            currMo.setProcessTime(Timestamp.valueOf(LocalDateTime.now()));
            workFlowFrameRep.save(currMo);
            // 调入审批驳回后处理
            errMsg = postCarTransferInDisagreeProcess(currMo);
            if ("00".equals(errMsg)) { // 正常返回
                return new ResultData("true", null, null);
            } else {
                throw new Exception();
            }
        } catch (Exception e) {
            logger.error(errMsg, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new ResultData("false", errMsg, null);
        }
    }

    @Override
    public ResultData agreeTransferOutApproval(AgreeTransferOutApproval request) {
        logger.info("agreeTransferOutApproval，params json = " + JsonObjectUtils.writeAsJson(request));
        String errMsg = "调车调出审批通过异常";
        try {
            // 根据id获取待修改的审批记录
            PushApprovalWorkFlowModel currMo = workFlowFrameRep.findOne(request.transactionId);
            if (currMo == null) {
                errMsg = "找不到对应的审批记录";
                throw new Exception();
            }
            // 修改审批记录并保存
            currMo.setApprovalStatus(ApprovalUtils.AGREE);
            currMo.setRemark(request.remark);
            currMo.setProcessTime(Timestamp.valueOf(LocalDateTime.now()));
            workFlowFrameRep.save(currMo);

            // 获取全部调出审批流水
            List<PushApprovalWorkFlowModel> transOutWorkFlow = workFlowFrameRep.getModelByTransactionCode(currMo.getTranscationCode());
            // 排序
            transOutWorkFlow.sort((PushApprovalWorkFlowModel m1, PushApprovalWorkFlowModel m2) -> m1.getStep().compareTo(m2.getStep()));
            // 获取记录对应的审批step
            String currentStep = currMo.getStep();
            // 获取当前审批人在流水中的索引
            Integer currIndex = getIndex(transOutWorkFlow, currentStep);
            if (currIndex == -1) {
                errMsg = "在流水中找不到对应的审批step";
                throw new Exception();
            }

            // 修改调车表记录
            Integer transferId = Integer.parseInt(currMo.getQuotedPriceCodeOrVin());
            CarTransferLogModel transLogMo = carTransLogRep.findOne(transferId);
            if (request.expectedLateMoneyInAccount != null && request.expectedLateMoneyInAccount.length() != 0) {
                transLogMo.setExpectedLateMoneyInAccount(Date.valueOf(LocalDate.parse(request.expectedLateMoneyInAccount)));
            }
            transLogMo.setExternalApplyDate(java.sql.Date.valueOf(LocalDate.now()));
            transLogMo.setExternalApplyUser(currMo.getUserName());
            carTransLogRep.save(transLogMo);

            // 获取全部调入审批流水
            List<PushApprovalWorkFlowModel> transInWorkFlow
                    = workFlowFrameRep.getWorkFlowByPermitTypeId(transLogMo.getInDealer(), ApprovalUtils.TRANSFER_IN, transLogMo.getId() + "");
            // 排序
            transInWorkFlow.sort((PushApprovalWorkFlowModel m1, PushApprovalWorkFlowModel m2) -> m1.getStep().compareTo(m2.getStep()));
            // 消息数据准备
            Lsh库存表Model stockMo = stockRep.findOne(transLogMo.getStockCode());
            String stepNum = currentStep.substring(4);
            if (!currIndex.equals(transOutWorkFlow.size() - 1)) { // 非调出最后一级审批
                // 保存给下一级审批人的消息
                String[] msgPar = {stockMo.get生产号(), stepNum};
                String msgContent = MessageFormat.format("生产号为{0}的调车调出{1}级审批已通过", (Object[]) msgPar);
                LshMsgUtils.getLshMsg(currMo.getPermit(), currMo.getUserName(),
                        transOutWorkFlow.get(currIndex + 1).getPermit(), transOutWorkFlow.get(currIndex + 1).getUserName(),
                        "调车调出", msgContent, currMo.getUserName(), transLogMo.getCustomTel());
//                // 调出审批通过后，要判断后面的审批人是否会根据审批分组自动通过
//                errMsg = sameManagerAccountAutoProcess(transInWorkFlow, transOutWorkFlow, currIndex + 1);
//                if (!"00".equals(errMsg)) throw new Exception();
                // 极光推送
                JsonObject json = JsonObjectUtils.getJsonObject(currMo.getType() + "", "1", stockMo.get车架号(), "", "", "");
                List<String> recList = new ArrayList<>();
                recList.add(transOutWorkFlow.get(currIndex + 1).getUserName());
                JPush.sendPushForAndroidAndIos(msgContent, msgContent, json, recList, JPush.Platforms.iMgt);
                return new ResultData("true", null, null);
            } else { // 调出最后一级审批
                // 调入审批通过后处理方法
                errMsg = postCarTransferOutAgreedProcess(currMo);
                if ("00".equals(errMsg)) { // 正常返回
                    return new ResultData("true", null, null);
                } else { // 异常返回
                    throw new Exception();
                }
            }
        } catch (Exception e) {
            logger.error(errMsg, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new ResultData("false", errMsg, null);
        }
    }

    @Override
    public ResultData disagreeTransferOutApproval(AgreeTransferOutApproval request) {
        logger.info("disagreeTransferOutApproval，params json = " + JsonObjectUtils.writeAsJson(request));
        String errMsg = "调车调出审批通过异常";
        try {
            // 根据id获取待修改的审批记录
            PushApprovalWorkFlowModel currMo = workFlowFrameRep.findOne(request.transactionId);
            if (currMo == null) {
                errMsg = "找不到对应的审批记录";
                throw new Exception();
            }
            // 修改审批记录并保存
            currMo.setApprovalStatus(ApprovalUtils.DISAGREE);
            currMo.setRemark(request.remark);
            currMo.setProcessTime(Timestamp.valueOf(LocalDateTime.now()));
            workFlowFrameRep.save(currMo);
            Integer transferId = Integer.parseInt(currMo.getQuotedPriceCodeOrVin());
            CarTransferLogModel transLogMo = carTransLogRep.findOne(transferId);
            transLogMo.setLogisticsStatus("");
            transLogMo.setExternalApplyDate(null);
            Lsh库存表Model stockMo = stockRep.findOne(transLogMo.getStockCode());
            Lsh车型Model carMo = carRep.findOne(stockMo.get车型编号());

            // 修改物流状态与外部申请日
            stockRep.updateLogisticsStatusById(stockMo.get库存编号(), null, null);
            // 获取全部调入审批流水
            List<PushApprovalWorkFlowModel> transInWorkFlow
                    = workFlowFrameRep.getWorkFlowByPermitTypeId(transLogMo.getInDealer(), ApprovalUtils.TRANSFER_IN, transLogMo.getId() + "");

            PushApprovalWorkFlowModel maAppMo = transInWorkFlow.get(transInWorkFlow.size() - 1);

            //驳回之后修改为“SC/CDO可见”
            Lsh库存内部可见Model stockVisibleMo = stockVisibleRep.findBystocknumber(stockMo.get库存编号());
            if (stockVisibleMo != null) {
                stockVisibleRep.updateStatusById("SC/CDO可见", stockVisibleMo.get库存内部可见编号());
            }
            String[] msgPar = {transLogMo.getInternalApplyDate() + "", stockMo.get生产号(), carMo.get车型详细(),
                    LocalDate.now() + "", transLogMo.getCustomName(), transLogMo.getCustomTel()};
            String msgContent = MessageFormat.format("您于{0}提交的生产号为{1},车款为{2}的调车申请于{3}未通过外部审批," +
                    "顾客姓名：{4},顾客电话：{5}", (Object[]) msgPar);

            // 发送消息到调入经销商销售行政，确认审批驳回
            LshMsgUtils.getLshMsg(currMo.getPermit(), currMo.getUserName(), maAppMo.getPermit(), transLogMo.getInternalApplyUser(),
                    "调车调出", msgContent, currMo.getUserName(), transLogMo.getCustomTel());

            // 他店调出驳回后，发送消息到调入经销商管理层APP，确认审批驳回
            LshMsgUtils.getLshMsg(currMo.getPermit(), currMo.getUserName(), maAppMo.getPermit(), maAppMo.getUserName(),
                    "调车调出", msgContent, currMo.getUserName(), transLogMo.getCustomTel());
            JsonObject json = JsonObjectUtils.getJsonObject("8", "2", currMo.getQuotedPriceCodeOrVin(), "", "", "");
            List<String> recList = new ArrayList<>();
            recList.add(maAppMo.getUserName());
            JPush.sendPushForAndroidAndIos(msgContent, msgContent, json, recList, JPush.Platforms.iMgt);
            return new ResultData("true", null, null);
        } catch (Exception e) {
            logger.error(errMsg, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new ResultData("false", errMsg, null);
        }
    }

    @Override
    public ResultData transferOut(String stockId, String user) {
        logger.info("transferOut传入参数为:" + JsonObjectUtils.writeAsJson(stockId));
        String errMsg = "出库操作异常";
        try {
            Lsh库存表Model stockMo = stockRep.findOne(Integer.parseInt(stockId));
            CarTransferLogModel transMo = carTransLogRep.findByStockId(stockMo.get库存编号()).get(0);
            String isEmergency = transMo.getIsEmegency();
            String lStatus = transMo.getLogisticsStatus();
            // 什么时候可以出库(不成立）
            if (!
                    (
                            ("0".equals(isEmergency) && "调出申请确认".equals(lStatus)) // 紧急调车，审批完成可以出库
                                    ||
                                    ("1".equals(isEmergency) && "调车款项到账".equals(transMo.getFinancialStatus())) // 非紧急，收款后可以出库
                    )
                    ) {
                return new ResultData("false", "该车不处于可出库状态", null);
            }
            // 什么时候不能出库
            if ("调出出库".equals(lStatus) || "调入入库".equals(lStatus)) {
                return new ResultData("false", "该车已经出库");
            }
            // 修改库存表数据
            stockMo.set调车物流状态("调出出库");
            stockMo.set所属经销商(transMo.getInDealer());
            stockMo.set入库日期(null);
            // 修改调车表数据
            transMo.setLogisticsStatus("调出出库");
            transMo.setStockOutDate(java.sql.Date.valueOf(LocalDate.now()));
            transMo.setStockOutUser(user);
            transMo.setModifyDate(Timestamp.valueOf(LocalDateTime.now()));
            return new ResultData("true", null, null);
        } catch (Exception e) {
            logger.warn(errMsg, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new ResultData("false", errMsg, null);
        }

    }

    // 调入审批通过后处理流程
    private String postCarTransferInAgreedProcess(List<PushApprovalWorkFlowModel> transInWorkFlow, PushApprovalWorkFlowModel currMo) {
        String errMsg = "调入审批通过后处理异常";
        try {
            // 调车id
            Integer transId = Integer.parseInt(currMo.getQuotedPriceCodeOrVin());
            // 调车记录
            CarTransferLogModel transLogMo = carTransLogRep.findById(transId);
            if (transLogMo == null) {
                errMsg = "找不到对应的调车记录";
                throw new Exception();
            }
            Lsh库存表Model stockMo = stockRep.findOne(transLogMo.getStockCode());
            Lsh车型Model carMo = carRep.findOne(stockMo.get车型编号());
            // 生成调出审批流，这个过程中处理了对于调出方的消息推送
            PushApprovalWorkFlowModel tmpModel = new PushApprovalWorkFlowModel();
            tmpModel.setPermit(transLogMo.getOutDealer());
            tmpModel.setType(ApprovalUtils.TRANSFER_OUT);
            tmpModel.setQuotedPriceCodeOrVin(transId + "");
            ResultData rd = approvalService.addApprovalWorkFlow(tmpModel, currMo.getUserName());
            if ("false".equals(rd.getResult())) { // 如果调用失败则返回消息
                errMsg = rd.getMessage();
                throw new Exception();
            }
            // 修改库存表记录
            Lsh库存表Model stockModel = stockRep.findOne(transLogMo.getStockCode());
            stockModel.set调车物流状态("调入申请确认");
            stockModel.set调入外部申请日(Date.valueOf(LocalDate.now()));
            // 修改调车表对应的记录
            transLogMo.setLogisticsStatus("调入申请确认");
            transLogMo.setExternalApplyDate(Date.valueOf(LocalDate.now()));
            // 找到新建的调出审批流水
            List<PushApprovalWorkFlowModel> transOutWorkFlow
                    = workFlowFrameRep.getWorkFlowByPermitTypeId(transLogMo.getOutDealer(), ApprovalUtils.TRANSFER_OUT, transId + "");
            // 排序
            transOutWorkFlow.sort((PushApprovalWorkFlowModel m1, PushApprovalWorkFlowModel m2) -> m1.getStep().compareTo(m2.getStep()));
            // 自动处理重复总经理审批
            errMsg = sameManagerAccountAutoProcess(transInWorkFlow, transOutWorkFlow);
            if (!"00".equals(errMsg)) throw new Exception();

            // 保存给销售行政的消息
            String msgContentForSa = MessageContext.getPostCarTransferInProcessForSaleAdmin(
                    transLogMo.getInternalApplyDate() + "", stockMo.get生产号(), carMo.get车型详细(),
                    transLogMo.getCustomName(), transLogMo.getCustomTel(), DefaultValueConstant.SET_PASS);
            LshMsgUtils.getLshMsg(currMo.getPermit(), currMo.getUserName(),
                    currMo.getPermit(), transLogMo.getInternalApplyUser(),
                    MessageType.Type.getName(MSG_TYPE_SHUNTING_IN),
                    msgContentForSa, currMo.getUserName(), transLogMo.getCustomTel());
            // 给调出方审批人发消息
            String dealerName = dealerRep.findNameByPermit(stockMo.get调入经销商());
            String msgContentForNext = MessageContext.getPostCarTransferInProcess(dealerName, stockMo.get生产号(), carMo.get车型详细());
            PushApprovalItemSettingModel workFlowSetMo =
                    workFlowSetRep.getModelByPermitAndType(stockMo.get所属经销商(), ApprovalUtils.TRANSFER_OUT);
            if (workFlowSetMo != null) {
                LshMsgUtils.getLshMsg(stockMo.get调入经销商(), currMo.getUserName(),
                        stockMo.get调出经销商(), workFlowSetMo.getStep1(),
                        MessageType.Type.getName(MSG_TYPE_SHUNTING_IN),
                        msgContentForNext, currMo.getUserName(), transLogMo.getCustomTel());
                // 极光推送给下级审批人
                JsonObject json = JsonObjectUtils.getJsonObject(ApprovalUtils.TRANSFER_OUT + "", ApprovalUtils.AGREE, stockMo.get车架号(), null, null, null);
                List<String> recList = Lists.newArrayList();
                recList.add(workFlowSetMo.getStep1());
                JPush.sendMsgToMgtAi(msgContentForNext, msgContentForNext, json, recList);
            } // 找不到调出消息发送人，为不影响流程，不抛出异常
            return "00";
        } catch (Exception e) {
            logger.error(errMsg, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return errMsg;
        }
    }

    // 调入审批驳回后处理
    private String postCarTransferInDisagreeProcess(PushApprovalWorkFlowModel currModel) {
        String errMgs = "调入审批驳回后处理异常";
        try {
            // 调车事务号
            Integer transId = Integer.parseInt(currModel.getQuotedPriceCodeOrVin());
            CarTransferLogModel transMo = carTransLogRep.findOne(transId);
            transMo.setLogisticsStatus("");
            transMo.setExternalApplyDate(null);
            Lsh库存表Model stockMo = stockRep.findOne(transMo.getStockCode());
            stockMo.set调车物流状态(null);
            stockMo.set调入外部申请日(null);
            stockRep.save(stockMo);
            // 驳回之后修改为“SC/CDO可见”
            Lsh库存内部可见Model innerVisibleMo = stockVisibleRep.findBystocknumber(stockMo.get库存编号());
            if (innerVisibleMo != null) {
                stockVisibleRep.updateStatusById("SC/CDO可见", innerVisibleMo.get库存内部可见编号());
            }
            // 保存给销售行政的消息
            Lsh车型Model carMo = carRep.findOne(stockMo.get车型编号());
            String content = MessageContext.getPostCarTransferInProcessForSaleAdmin(transMo.getInternalApplyDate() + "",
                    stockMo.get生产号(), carMo.get车型详细(), transMo.getCustomName(), transMo.getCustomTel(),
                    DefaultValueConstant.SET_FULL);
            LshMsgUtils.getLshMsg(currModel.getPermit(), currModel.getUserName(), currModel.getPermit(),
                    transMo.getInternalApplyUser(), "调车调入", content, currModel.getUserName(), transMo.getCustomTel());
            return "00";
        } catch (Exception e) {
            logger.error(errMgs, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return errMgs;
        }
    }

    /**
     * 调出审批通过后处理
     *
     * @param currModel 调出审批最后一级审批流
     * @return 字符串状态
     */
    private String postCarTransferOutAgreedProcess(PushApprovalWorkFlowModel currModel) {
        String errMsg = "调出后处理异常";
        try {
            // 调车id
            Integer transId = Integer.parseInt(currModel.getQuotedPriceCodeOrVin());
            // 调车记录
            CarTransferLogModel transLogMo = carTransLogRep.findById(transId);
            // 修改调车记录
            transLogMo.setOutConfirmUser(currModel.getUserName());
            transLogMo.setOutConfirmDate(java.sql.Date.valueOf(LocalDate.now()));
            transLogMo.setLogisticsStatus("调出申请确认");
            transLogMo.setFinancialStatus("等待开调车增值票/付款");
            transLogMo.setOutConfirmDate(Date.valueOf(LocalDate.now()));
            carTransLogRep.save(transLogMo);
            // 库存记录
            Lsh库存表Model stockMo = stockRep.findOne(transLogMo.getStockCode());
            // 车型
            Lsh车型Model carMo = carRep.findOne(stockMo.get车型编号());
            // 找到对应的调入审批流水
            List<PushApprovalWorkFlowModel> transInWorkFlow
                    = workFlowFrameRep.getWorkFlowByPermitTypeId(transLogMo.getInDealer(), ApprovalUtils.TRANSFER_IN, transId + "");
            // 排序
            transInWorkFlow.sort((PushApprovalWorkFlowModel m1, PushApprovalWorkFlowModel m2) -> m1.getStep().compareTo(m2.getStep()));
            // 修改调车物流状态为"调出申请确认"，调出财务状态为'等待开调车增值票/付款'，告知A店和B店财务。写入调出确认日期
            stockRep.updateLshStoreStaById(stockMo.get库存编号(), "调出申请确认", new java.util.Date(), "等待开调车增值票/付款");

            // 为消息准备
            PushApprovalWorkFlowModel managerMo = transInWorkFlow.get(transInWorkFlow.size() - 1);
            String inDealerCn = dealerRep.findNameByPermit(transLogMo.getInDealer());
            String outDealerCn = dealerRep.findNameByPermit(transLogMo.getOutDealer());

            // 发送消息到调入方销售行政
            String isEmergencyCn = "0".equals(transLogMo.getIsEmegency()) ? "紧急" : "非紧急";
            String[] msgParSa = {transLogMo.getInternalApplyDate() + "", stockMo.get生产号(), carMo.get车型详细(),
                    LocalDate.now() + "", outDealerCn, isEmergencyCn, transLogMo.getExpectedLateInStockDate() + "",
                    transLogMo.getCustomName(), transLogMo.getCustomTel()};
            String msgContentSa = MessageFormat.format("贵司于{0}提交的生产号为{1},车款为{2}的调车申请于{3}已经通过外部审批," +
                    "调出经销商为{4},属于{5}调车,最晚入库日期为{6},顾客姓名：{7},顾客电话：{8}", (Object[]) msgParSa);
            LshMsgUtils.getLshMsg(currModel.getPermit(), currModel.getUserName(), managerMo.getPermit(), transLogMo.getInternalApplyUser(),
                    "调车调出", msgContentSa, currModel.getUserName(), transLogMo.getCustomTel());

            // 检查消息设置，是否发送消息到调入方财务
            MessageSettingModel msgSetMoInFi = msgSetRep.findByPermitAndType(stockMo.get调入经销商(), "2", "1");
            if (msgSetMoInFi != null) {
                用户Model userMoInFi = userRep.findByPermitAndUserName(stockMo.get调入经销商(), "财务专员", msgSetMoInFi.getUser());
                if (userMoInFi != null) {
                    String latestDate = transLogMo.getExpectedLateMoneyInAccount() == null ? "" :
                            ",最晚款项到账日期为" + transLogMo.getExpectedLateMoneyInAccount() + "";
                    String[] msgParFiIn = {transLogMo.getInternalApplyDate() + "", stockMo.get生产号(), carMo.get车型详细(),
                            transLogMo.getOutConfirmDate() + "", outDealerCn, stockMo.get协商调车款项金额() + "",
                            latestDate, transLogMo.getCustomName(), transLogMo.getCustomTel()};
                    String msgContentFiIn = MessageFormat.format("贵司于{0}提交的生产号为{1},车款为{2}的调车申请于{3}已经通过外部审批," +
                            "调出经销商为{4},协商调车款项金额（不含税）为{5}元{6},顾客姓名：{7},顾客电话：{8}", (Object[]) msgParFiIn);
                    LshMsgUtils.getLshMsg(currModel.getPermit(), currModel.getUserName(), userMoInFi.get许可(),
                            userMoInFi.get用户名(), "调车调出", msgContentFiIn, currModel.getUserName(), transLogMo.getCustomTel());
                }
            }

            // 检查消息设置，是否要发送到调出方行政
            MessageSettingModel msgSetMo = msgSetRep.findByPermitAndType(currModel.getPermit(), "3", "1");
            if (msgSetMo != null) {
                用户Model userMoSa = userRep.findByPermitAndUserName(msgSetMo.getPermit(), "销售行政", msgSetMo.getUser());
                if (userMoSa != null) {
                    String[] msgParSaOut = {LocalDate.now() + "", stockMo.get生产号(), carMo.get车型详细(), inDealerCn,
                            isEmergencyCn, transLogMo.getExpectedLateInStockDate() + ""};
                    String msgContentSaOut = MessageFormat.format("贵司管理层于{0}已经确认生产号为,车款为{1}的车辆将调出," +
                            "调入经销商为{2},属于{3}调车,最晚入库日期为{4}", (Object[]) msgParSaOut);
                    LshMsgUtils.getLshMsg(currModel.getPermit(), currModel.getUserName(), userMoSa.get许可(), userMoSa.get用户名(),
                            "调车调出", msgContentSaOut, currModel.getUserName(), transLogMo.getCustomTel());
                }
            }

            // 检查消息设置，是否发送消息到调出方财务
            MessageSettingModel msgSetOutFiMo = msgSetRep.findByPermitAndType(currModel.getPermit(), "4", "1");
            if (msgSetOutFiMo != null) {
                用户Model userOutFiMo = userRep.findByPermitAndUserName(stockMo.get所属经销商(), "财务专员", msgSetOutFiMo.getUser());
                if (userOutFiMo != null) {
                    String latestDate = transLogMo.getExpectedLateMoneyInAccount() == null ? "" :
                            ",最晚款项到账日期为" + transLogMo.getExpectedLateMoneyInAccount();
                    String[] msgParOutFi = {transLogMo.getOutConfirmDate() + "", stockMo.get生产号(), carMo.get车型详细(),
                            inDealerCn, stockMo.get协商调车款项金额() + "", latestDate};
                    String msgContentOutFi = MessageFormat.format("贵司管理层于{0}已经确认生产号为{1},车款为{2}的车辆将调出," +
                            "调入经销商为{3},协商调车款项金额（不含税）为{4}元{5}", (Object[]) msgParOutFi);
                    LshMsgUtils.getLshMsg(currModel.getPermit(), currModel.getUserName(), userOutFiMo.get许可(),
                            userOutFiMo.get用户名(), "调车调出", msgContentOutFi, currModel.getUserName(), transLogMo.getCustomTel());
                }
            }

            // 发送消息到调入方管理层app
            String[] msgPar = {transLogMo.getInternalApplyDate() + "", stockMo.get生产号(), carMo.get车型详细(),
                    LocalDate.now() + "", transLogMo.getCustomName(), transLogMo.getCustomTel()};
            String msgContent = MessageFormat.format("您于{0}提交的生产号为{1},车款为{2}的调车申请于{3}已通过外部审批,顾客姓名：{4},顾客电话：{5}"
                    , (Object[]) msgPar);
            LshMsgUtils.getLshMsg(currModel.getPermit(), currModel.getUserName(), managerMo.getPermit(), managerMo.getUserName(),
                    "调车调出", msgContent, currModel.getUserName(), transLogMo.getCustomTel());
            // JPush推送
            JsonObject json = JsonObjectUtils.getJsonObject("9", "1", stockMo.get车架号(), "", "", "");
            List<String> recList = new ArrayList<>();
            recList.add(managerMo.getUserName());
            JPush.sendMsgToMgtAi(msgContent, msgContent, json, recList);
            return "00";
        } catch (Exception e) {
            logger.error(errMsg, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return errMsg;
        }
    }

    // 根据step取得当前下标
    private Integer getIndex(List<PushApprovalWorkFlowModel> workFlow, String step) {
        int i = 0;
        for (; i < workFlow.size(); i++) {
            PushApprovalWorkFlowModel pModel = workFlow.get(i);
            if (pModel.getStep().equals(step)) {
                return i;
            }
        }
        return -1;
    }

    // 检查该车是否可调
    private ResultData isTransferable(String dealer, Lsh库存表Model stockMo) {
        if (stockMo.get批发日期() == null) { // 未批发不可调
            return new ResultData("false", "该车还没有批发，不能调车", null);
        }
        if ("审批中".equals(stockMo.get车辆零售状态())) { // 审批中不可调
            return new ResultData("false", "该车处于审批状态，不能调车", null);
        }
        if ("已卖".equals(stockMo.get车辆零售状态())) { // 已卖不可调
            return new ResultData("false", "该车已卖，不能调车", null);
        }
        if (dealer.equals(stockMo.get所属经销商())) {
            return new ResultData("false", "本店车辆不可以调入", null);
        }
        String isTransferComplete = isTransferComplete(stockMo);
        if ("00".equals(isTransferComplete)) {
            return new ResultData("true", "该车辆可以被调", null);
        }
        // 其他情况不能调车
        return new ResultData("false", "该车已经在调车流程中，不能调车", null);
    }

    public String isTransferComplete(Lsh库存表Model stockMo) {
        String inDlr = stockMo.get调入经销商();
        if (inDlr == null // 从未调过车
                || (stockMo.get所属经销商().equals(inDlr) && "调车款项到账".equals(stockMo.get调车财务状态())
                && "调入入库".equals(stockMo.get调车物流状态()))) { // 上次调车已经完成
            return "00";
        }
        // 有调车，但被驳回
        List<CarTransferLogModel> transMoLi = carTransLogRep.findByStockId(stockMo.get库存编号());
        if (transMoLi.size() != 0) {
            CarTransferLogModel lastTrans = transMoLi.get(0);
            List<PushApprovalWorkFlowModel> pMoLi1 = workFlowFrameRep.getWorkFlowByPermitTypeId(lastTrans.getInDealer(),
                    ApprovalUtils.TRANSFER_IN, lastTrans.getId() + "");
            for (PushApprovalWorkFlowModel mo : pMoLi1) { // 调入被驳回
                if (ApprovalUtils.DISAGREE.equals(mo.getApprovalStatus())) {
                    return "00";
                }
            }
            List<PushApprovalWorkFlowModel> pMoLi2 = workFlowFrameRep.getWorkFlowByPermitTypeId(lastTrans.getOutDealer(),
                    ApprovalUtils.TRANSFER_OUT, lastTrans.getId() + "");
            for (PushApprovalWorkFlowModel mo : pMoLi2) { // 调出被驳回
                if (ApprovalUtils.DISAGREE.equals(mo.getApprovalStatus())) {
                    return "00";
                }
            }
        }
        return "01"; // 调车未完成
    }

    // 比较调出审批人index与所有调入审批人的分组
    // 如果index的账号，与调入审批人中的账号，有相同的审批分组，则修改为通过，并判断调出流程是否结束，否则返回
    // 如果流程没结束，继续判断index + 1与所有调入审批人的情况，有则修改，并判断调出流程是否结束，否则返回
    // 如果调出流程结束，进行调出流程后处理，并返回
//    private String sameManagerAccountAutoProcess(List<PushApprovalWorkFlowModel> transInWorkFlow,
//                                                 List<PushApprovalWorkFlowModel> transOutWorkFlow,
//                                                 Integer index) {
//        String errMsg = "CTA调车自动处理异常";
//        try {
//            if (index < 0 || index > transOutWorkFlow.size() - 1) {
//                errMsg = "sameManagerAccountAutoProcess方法的index越界";
//                throw new Exception();
//            }
//            // 调出记录
//            PushApprovalWorkFlowModel transOutModel = transOutWorkFlow.get(index);
//            // 调出审批人分组
//            用户Model userOutMo = userRep.findOne(transOutModel.getUserName());
//            if (userOutMo == null) {
//                errMsg = "sameManagerAccountAutoProcess中的调出审批人找不到对应的用户";
//                throw new Exception();
//            }
//            String transOutGroup = userOutMo.getApprovalGroup();
//            for (PushApprovalWorkFlowModel transInModel : transInWorkFlow) {
//                用户Model userInMo = userRep.findOne(transInModel.getUserName());
//                if (userInMo == null) {
//                    errMsg = "sameManagerAccountAutoProcess中的调入审批人找不到对应的用户";
//                    throw new Exception();
//                }
//                // 调入审批人分组
//                String transInGroup = userInMo.getApprovalGroup();
//                if (transOutGroup.length() != 0 && transInGroup.length() != 0 && transOutGroup.equals(transInGroup)) { // 如果分组相同，将调出状态置1
//                    transOutModel.setApprovalStatus("1");
//                    logger.info(String.format("自动将调入审批人%s的调出审批流水%s处理为通过",
//                            transInModel.getUserName(), transOutModel.getId()));
//                    if (index == transOutWorkFlow.size() - 1) { // 如果是最后一级审批人通过，进行调出审批后处理
//                        errMsg = postCarTransferOutAgreedProcess(transOutWorkFlow.get(index));
//                        if (!"00".equals(errMsg)) {
//                            throw new Exception();
//                        }
//                    } else { // 否则对调出审批流下一个step，递推
//                        sameManagerAccountAutoProcess(transInWorkFlow, transOutWorkFlow, index + 1);
//                    }
//                }
//            }
//            return "00";
//        } catch (Exception e) {
//            logger.error(errMsg, e);
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return errMsg;
//        }
//    }

    /**
     * 需求：20170420 新需求，如果调出审批人中，与调入审批人中具有相同的分组，则该调出审批人作审批通过处理，且在此审批人之前的所有调出
     * 审批人标记为通过。
     * 开发：从最后一个审批人开始遍历调出审批流，如果在调入审批流中找到相同的审批人分组，修改这几个流水的审批状态为通过，并判断流程
     * 是否结束，这种情况只需要在调入审批结束的时候，check一下调出审批流的分组情况，逻辑比以前还简单
     *
     * @param transInWorkFlow  调入审批流
     * @param transOutWorkFlow 调出审批流
     * @return 状态字符串
     */
    private String sameManagerAccountAutoProcess(List<PushApprovalWorkFlowModel> transInWorkFlow,
                                                 List<PushApprovalWorkFlowModel> transOutWorkFlow) {
        String errMsg = "CTA调车自动处理异常";
        try {
            tag:
            for (int i = transOutWorkFlow.size() - 1; i >= 0; i--) {
                PushApprovalWorkFlowModel transOutModel = transOutWorkFlow.get(i); // 调出记录
                用户Model userOutMo = userRep.findOne(transOutModel.getUserName());
                if (userOutMo == null) {
                    errMsg = "sameManagerAccountAutoProcess中的调出审批人找不到对应的用户";
                    throw new Exception();
                }
                // 调出审批人分组
                String transOutGroup = userOutMo.getApprovalGroup();
                for (PushApprovalWorkFlowModel transInModel : transInWorkFlow) {
                    用户Model userInMo = userRep.findOne(transInModel.getUserName());
                    if (userInMo == null) {
                        errMsg = "sameManagerAccountAutoProcess中的调入审批人找不到对应的用户";
                        throw new Exception();
                    }
                    // 调入审批人分组
                    String transInGroup = userInMo.getApprovalGroup();
                    // 如果分组相同
                    if (transOutGroup.length() != 0 && transInGroup.length() != 0 && transOutGroup.equals(transInGroup)) {
                        for (int j = i; j >= 0; j--) {
                            // 将分组相同的审批人，及在调出审批流中此人之前的所有人，审批状态置为通过
                            PushApprovalWorkFlowModel toModifyMo = transOutWorkFlow.get(j);
                            toModifyMo.setApprovalStatus(ApprovalUtils.AGREE);
                            toModifyMo.setRemark("CTA");
                            toModifyMo.setProcessTime(Timestamp.valueOf(LocalDateTime.now()));
                            logger.info(String.format("自动将调入审批人%s的调出审批流水%s处理为通过",
                                    transInModel.getUserName(), transOutModel.getId()));
                        }
                        // 如果是最后一级审批人通过，进行调出审批后处理
                        if (transOutWorkFlow.get(transOutWorkFlow.size() - 1).getApprovalStatus().equals(ApprovalUtils.AGREE)) {
                            errMsg = postCarTransferOutAgreedProcess(transOutWorkFlow.get(transOutWorkFlow.size() - 1));
                            if (!"00".equals(errMsg)) throw new Exception();
                        } // 若不是最后一级审批人，不处理
                        break tag; // 因为是从最后一级开始遍历，只要有一个分组相同的账号处理了，其他分组相同的账号，就不用管了
                    } // 分组不同不处理
                }
            }
            return "00";
        } catch (Exception e) {
            logger.error(errMsg, e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return errMsg;
        }
    }
}
